home *** CD-ROM | disk | FTP | other *** search
- Path: news.th-darmstadt.de!news!enno
- From: enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner)
- Newsgroups: comp.lang.c++
- Subject: Re: a question about abstract base classes and libraries
- Date: 02 Feb 1996 16:33:56 GMT
- Organization: Fachbereich Informatik, TH Darmstadt
- Distribution: world
- Message-ID: <ENNO.96Feb2173356@kitz.inferenzsysteme.informatik.th-darmstadt.de>
- References: <4es0b1$au7@news.sdd.hp.com>
- NNTP-Posting-Host: kitz.intellektik.informatik.th-darmstadt.de
- In-reply-to: Laura Mansfield's message of 2 Feb 1996 03:27:29 GMT
-
- In article <4es0b1$au7@news.sdd.hp.com> Laura Mansfield <laura> writes:
-
- A question I'm hoping someone can answer ~
-
- I'm writing a library, lib.a, to be linked to by some client code that
- will use its services. The client code will include a file, lib.h, which
- defines the class interface to lib.a. The classes have member functions
- that the client code will use to do some inventory management.
-
- I'd like to hide the private data members of this class, and so have
- decided to create and abstract base class, and make visible to the client
- code only the derived class. To better explain, here's an example:
-
- In my library code:
-
- class Abstract
- {
-
- protected:
-
- int a;
- int b;
-
- public:
-
- virtual void func( void ) = 0;
- };
-
- In lib.h:
-
- class ClassA : public abstract
- {
-
- public:
-
- virtual void func( void );
- };
-
- But I'm beginning to realize I can't really do this w/out defining
- class Abstract in lib.h. I tried to do "class Abstract;" at the beginning
- of lib.h, but I think this only works for pointers.
-
- Can anyone help me w/ what to do here?
-
- When a class should be defined all its base-classes must already be defined.
- By reversing your approach, ie. let the clients exclusivly use the interface
- not a concrete implementation of the class, you can easily solve the problem.
- For example the class representing the interface namely 'Abstract' has to be
- public available to all clients and should therefore reside in 'lib.h':
-
- class Abstract {
- public:
- virtual ~Abstract() {}
- virtual void func() = 0;
- };
- <to be continueed>
-
- A possible implementation like 'ClassA' goes in 'lib.ph':
- #include "lib.h"
- class ClassA : public Abstract {
- public:
- void func();
- };
-
- and its implementation in 'lib.C':
- #include "lib.ph"
- void ClassA :: func() { /* - here goes the implementation - */ }
- <to be continueed>
-
- Clients must not use 'lib.ph' directly. They use 'lib.h' instead and don't
- care about a particular implementation. The problem that remains for a client
- is howto create an instance of a subclass of 'Abstract' without knowing what
- the subclass looks like.
- A commonly accepted solution is a so-called 'factory-class'. It provides a
- method for creating an instance of a specific implementation but returns
- a pointer to the underlying interface. For example:
-
- 'lib.h':
- ...
- typedef Abstract* (*ACF)();
- class AFactory {
- public:
- static void Set(ACF);
- static Abstract* CreateA();
-
- private:
- static ACF acf_;
- };
-
- 'lib.C':
- ...
- void AFactory :: Set(ACF acf) { acf_=acf; }
- Abstract* AFactory :: CreateA() { return acf_ ? (*acf_)() : new ClientA(); }
- ACF AFactory :: acf_=0;
-
- A client uses the factory to create the appropriate instances:
-
- client.C:
- #include "lib.h"
-
- void f()
- {
- Abstract* a=AFactory :: CreateA();
- ...
- }
-
- The standard-behavior for creating instances simply returns an instance of
- 'ClientA'. You can easily modify this behavior with the 'Set' method of
- 'AFactory'. There are other solutions to the problem of the instance-creation.
- Several nifty solutions are described in 'Design Patterns' book from E. Gamma,
- R. Helm, R. Johnson and J. Vlissides.
-
- Enno
-